home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / EAGLE.C < prev    next >
Text File  |  1993-08-09  |  24KB  |  801 lines

  1. /*
  2.  * Interface driver for the EAGLE board for KA9Q's TCP/IP on an IBM-PC ONLY!
  3.  *
  4.  *  Written by Art Goldman, WA3CVG - (c) Copyright 1987 All Rights Reserved
  5.  *  Permission for non-commercial use is hereby granted provided this notice
  6.  *  is retained.  For info call: (301) 997-3838.
  7.  *
  8.  *  10 Jan 88    ng6q    - Corrected IDLE comparison in doegstat.
  9.  *   6 Apr 88    ng6q    - Changed eg_raw to prevent calling egtxint with a
  10.  *              packet in sndbuf.  Initialized sndq and rcvq in
  11.  *              eg_attach.  Added carrier detect check before
  12.  *              slot time delay in egtxint.  Should make major
  13.  *              changes to egtxint to avoid delay loops while
  14.  *              masked for receive interrupts.
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include <dos.h>
  19. #include "global.h"
  20. #include "config.h"
  21. #ifdef EAGLE
  22. #include "mbuf.h"
  23. #include "iface.h"
  24. #include "pktdrvr.h"
  25. #include "netuser.h"
  26. #include "eagle.h"
  27. #include "n8530.h"
  28. #include "ax25.h"
  29. #include "trace.h"
  30. #include "pc.h"
  31. #include <time.h>
  32. #include "devparam.h"
  33.  
  34. static int32 eg_ctl __ARGS((struct iface *iface,int cmd,int set,int32 val));
  35. static int eg_raw __ARGS((struct iface *iface,struct mbuf *bp));
  36. static int eg_stop __ARGS((struct iface *iface,int temp));
  37. static void egchanparam __ARGS((struct egchan *hp));
  38. static void egexint __ARGS((struct egchan *hp));
  39. static void egrxint __ARGS((struct egchan *hp));
  40. static void egtxint __ARGS((struct egchan *hp));
  41. static void rts __ARGS((struct egchan *hp,int16 x));
  42. static void waitmsec __ARGS((int n));
  43.  
  44. static struct EGTAB Eagle[EGMAX];    /* Device table - one entry per card */
  45. static INTERRUPT (*eghandle[])() = {    /* handler interrupt vector table */
  46.     eg0vec,    
  47. };
  48. static struct egchan Egchan[2*EGMAX];    /* channel table - 2 entries per card */
  49. static int16 Egnbr;
  50.  
  51. /* Master interrupt handler.  One interrupt at a time is handled.
  52.  * here. Service routines are called from here.
  53.  */
  54. void
  55. egint(dev)
  56. int dev;
  57. {
  58.     char st;
  59.     int16 pcbase;
  60.     struct egchan *hp;
  61.  
  62.     Eagle[dev].ints++;
  63.     pcbase = Eagle[dev].addr;
  64.  
  65.     /* Read interrupt status register from channel A */
  66.     while((st = read_scc(pcbase+CHANA+CTL,R3)) != 0) {
  67.         /* Use IFs to process ALL interrupts pending
  68.          * because we need to check all interrupt conditions
  69.          */
  70.         if (st & CHARxIP) {
  71.             /* Channel A Rcv Interrupt Pending */
  72.             hp = &Egchan[2 * dev];
  73.             egrxint(hp);
  74.         } else if (st & CHATxIP) {
  75.             /* Channel A Transmit Int Pending */
  76.             hp = &Egchan[2 * dev];
  77.             egtxint(hp);
  78.         } else if (st & CHAEXT) {
  79.             /* Channel A External Status Int */
  80.             hp = &Egchan[2 * dev];
  81.             egexint(hp);
  82.         } else if (st & CHBRxIP) {
  83.             /* Channel B Rcv Interrupt Pending */
  84.             hp = &Egchan[(2 * dev)+1];
  85.             egrxint(hp);
  86.         } else if (st & CHBTxIP) {
  87.             /* Channel B Transmit Int Pending */
  88.             hp = &Egchan[(2 * dev)+1];
  89.             egtxint(hp);
  90.         } else if (st & CHBEXT) {
  91.             /* Channel B External Status Int */
  92.             hp = &Egchan[(2 * dev)+1];
  93.             egexint(hp);
  94.         }
  95.         /* Reset highest interrupt under service */
  96.         write_scc(hp->base+CTL,R0,RES_H_IUS);
  97.     } /* End of while loop on int processing */
  98. }
  99.  
  100. /* Eagle SIO External/Status interrupts
  101.  * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM.
  102.  * Receiver automatically goes to Hunt on an abort.
  103.  *
  104.  * If the Tx Underrun interrupt hits, change state and
  105.  * issue a reset command for it, and return.
  106.  */
  107. static void
  108. egexint(hp)
  109. struct egchan *hp;
  110. {
  111.     char st;
  112.  
  113.     hp->exints++;
  114.     DISABLE();
  115.  
  116.     st = read_scc(hp->base+CTL,R0);     /* Fetch status */
  117.  
  118.     /* Check for Tx UNDERRUN/EOM - only in Transmit Mode */
  119.     if((hp->rstate==0) && (st & TxEOM)) {
  120.         /* if in UNDERRUN, go to FLAGOUT state
  121.          * see explanation under egtxint()
  122.          * CRC & FLAG now going out, so
  123.          * wait for Tx BUffer Empty int
  124.          */
  125.  
  126.         /* If we are not in underrun, this is an unexpected
  127.          * underrun.  EOM bit should be set, so the SCC will
  128.          * now send an abort
  129.          */
  130.  
  131.         if(hp->tstate == UNDERRUN)
  132.             hp->tstate = FLAGOUT;
  133.  
  134.         /* Tx Buff EMPTY interrupt occurs after CRC is sent */
  135.     }
  136.  
  137.     /* Receive Mode only
  138.      * This triggers when hunt mode is entered, & since an ABORT
  139.      * automatically enters hunt mode, we use that to clean up
  140.      * any waiting garbage
  141.      */
  142.     if((hp->rstate == ACTIVE) && (st & BRK_ABRT)) {
  143.         hp->rcp = hp->rcvbuf->data;
  144.         hp->rcvbuf->cnt = 0;          /* rewind on DCD transition */
  145.         hp->aborts++;              /* nbr aborts * 2 */
  146.     }
  147.  
  148.     /* reset external status latch */
  149.     write_scc(CTL+hp->base,R0,RES_EXT_INT);
  150.  
  151.     RESTORE();
  152. }
  153.  
  154. /* EG receive interrupt handler. The first receive buffer is pre-allocated
  155.  * in the init routine.  Thereafter, it is filled here, queued out, and a
  156.  * new one acquired.  CRC, OVERRUN and TOOBIG errors merely 'rewind' the
  157.  * pointers and reuse the same buffer.
  158.  */
  159. static void
  160. egrxint(hp)
  161. struct egchan *hp;
  162. {
  163.     char rse;
  164.     struct mbuf *bp;
  165.     struct phdr *phdr;
  166.  
  167.     int16 base = hp->base;
  168.  
  169.     hp->rxints++;
  170.     DISABLE();
  171.  
  172.     if ((read_scc(base+CTL,R0)) & Rx_CH_AV) {
  173.         /* there is a char to be stored
  174.          * read special condition bits before reading the data char
  175.          */
  176.         rse = read_scc(hp->base+CTL,R1); /* get status byte from R1 */
  177.         if(rse & Rx_OVR) {
  178.             /* Rx overrun - toss buffer */
  179.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  180.             hp->rcvbuf->cnt = 0;
  181.             hp->rstate = RXERROR;    /* set error flag */
  182.             hp->rovers++;        /* count overruns */
  183.         } else if(hp->rcvbuf->cnt >= hp->bufsiz) {
  184.             /* Too large -- toss buffer */
  185.             hp->toobig++;
  186.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  187.             hp->rcvbuf->cnt = 0;
  188.             hp->rstate = TOOBIG;    /* when set, chars are not stored */
  189.         }
  190.         /* ok, we can store the received character now */
  191.         if(hp->rstate == ACTIVE) {        /* If no errors... */
  192.             *hp->rcp++ = inportb(base+DATA);    /* char to rcv buff */
  193.             hp->rcvbuf->cnt++;            /* bump count */
  194.         } else {
  195.             /* got to empty FIFO */
  196.             (void) inportb(base+DATA);
  197.             write_scc(hp->base+CTL,R0,ERR_RES);    /* reset err latch */
  198.             hp->rstate = ACTIVE;
  199.         }
  200.     }
  201.     /* char has been stored
  202.      * read special condition bits
  203.      */
  204.     rse = read_scc(hp->base+CTL,R1);     /* get status byte from R1 */
  205.  
  206.     /* The End of Frame bit is ALWAYS associated with a character,
  207.      * usually, it is the last CRC char.  Only when EOF is true can
  208.      * we look at the CRC byte to see if we have a valid frame
  209.      */
  210.     if(rse & END_FR) {
  211.         hp->rxframes++;
  212.         /* END OF FRAME -- Make sure Rx was active */
  213.         if(hp->rcvbuf->cnt > 0) {        /* any data to store */
  214.             /* looks like a frame was received
  215.              * now is the only time we can check for CRC error
  216.              */
  217.             if((rse & CRC_ERR) || (hp->rstate > ACTIVE) || (hp->rcvbuf->cnt < 10)) {
  218.                 /* error occurred; toss frame */
  219.                 if(rse & CRC_ERR)
  220.                     hp->crcerr++;    /* count CRC errs */
  221.                 if(hp->rstate == RXERROR)
  222.                     hp->rovers++;
  223.                 /* don't throw away buffer -
  224.                  * merely reset the pointers
  225.                  */
  226.                 hp->rcp = hp->rcvbuf->data;
  227.                 hp->rcvbuf->cnt = 0;
  228.             } else {
  229.                 /* Here we have a valid frame */
  230.                 hp->rcvbuf->cnt -= 2;           /* Toss 2 crc bytes */
  231.                 bp = alloc_mbuf(sizeof(struct phdr));
  232.                 bp->cnt = sizeof(struct phdr);
  233.                 phdr = (struct phdr *)bp->data;
  234.                 phdr->type = CL_AX25;
  235.                 phdr->iface = hp->iface;
  236.                 bp->next = hp->rcvbuf;
  237.                 enqueue(&Hopper,bp);       /* queue it in */
  238.  
  239.                 /* packet queued - get buffer for next frame */
  240.                 hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  241.                 hp->rcp = hp->rcvbuf->data;
  242.                 hp->rcvbuf->cnt = 0;
  243.                 if(hp->rcvbuf == NULLBUF) {
  244.                     /* No memory, abort receiver */
  245.                     RESTORE();
  246.                     tputs("DISASTER! Out of Memory for Receive!\n");
  247.                     write_scc(CTL+base,R3,Rx8);
  248.                     return;
  249.                 }
  250.             } /* end good frame queued */
  251.         }  /* end check for active receive upon EOF */
  252.         hp->rstate = ACTIVE;    /* and clear error status */
  253.     } /* end EOF check */
  254.     RESTORE();
  255. }
  256.  
  257. /* egchan transmit interrupt service routine
  258.  *
  259.  * The state variable tstate, along with some static pointers,
  260.  * represents the state of the transmit "process".
  261.  */
  262. static void
  263. egtxint(hp)
  264. struct egchan *hp;
  265. {
  266.     int c;
  267.     int16 base = hp->base;
  268.  
  269.     DISABLE();
  270.  
  271.     if(hp->tstate != DEFER && hp->tstate)
  272.         hp->txints++;
  273.  
  274.     switch(hp->tstate) {
  275.     case FLAGOUT:
  276.         /* Here after CRC sent and Tx interrupt fires.
  277.          * To give the SCC a chance to get the FLAG
  278.          * out, we delay 100 Ms
  279.          */
  280.         hp->tstate = IDLE;    /* fall thru to IDLE */
  281.         waitmsec(10);        /* 100 msec wait for flag Tx */
  282.         /* Note, it may be possible to stuff out a
  283.          * meaningless character, wait for the interrupt
  284.          * then go to idle.  A delay is absolutely necessary
  285.          * here else the packet gets truncated prematurely
  286.          * when no other packet is waiting to be sent.
  287.          * IDLE state indicates either we are starting a brand new packet
  288.          * as a result of its being queued for transmission (egtxint called
  289.          * from eg_raw), or after a frame has been transmitted (as a
  290.          * result of a Tx buffer empty interrupt after the CRC/FLAG
  291.          */
  292.     case IDLE:
  293.         /* Transmitter idle. Find a frame for transmission */
  294.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF) {
  295.             /* Nothing to send - return to receive mode
  296.              * Tx OFF now - flag should have gone
  297.              */
  298.             rts(hp,OFF);
  299.             RESTORE();
  300.             return;
  301.         }
  302.         /* If a buffer to send, we drop thru here */
  303.     case DEFER:        /* we may have deferred prev xmit attempt */
  304.         /* PPERSIST CALCULATION: we use the lower byte of the
  305.          * 8253 timer 0 count, as a random number (0-255).
  306.          * If the persist value is higher, wait one slot time
  307.          */
  308.         if(hp->persist >= peekb(0x40,0x6c))
  309.             waitmsec(hp->slotime);
  310.  
  311.         /* Check DCD so we don't step on a frame being received */
  312.         /* DCD is ACTIVE LOW on the SCC DCD pin, but the bit in R0 */
  313.         /* is SET when DCD is ACTIVE!! */
  314.  
  315.         if((read_scc(base+CTL,R0) & DCD) > 0) { /* Carrier Detected? */
  316.             hp->tstate = DEFER;    /* defer xmit */
  317.             /* don't release dequeued buffer...*/
  318.             RESTORE();
  319.             return;
  320.         }
  321.  
  322.         rts(hp,ON);   /* Transmitter on */
  323.         /* ints not enabled yet */
  324.  
  325.         /* Get next char to send */
  326.         c = PULLCHAR(&hp->sndbuf);        /* one char at a time */
  327.         write_scc(CTL+base,R0,RES_Tx_CRC);    /* reset for next frame */
  328.         outportb(base+DATA,c);        /* First char out now */
  329.  
  330.         /* select transmit interrupts to enable */
  331.  
  332.         write_scc(CTL+base,R15,TxUIE);        /* allow Underrun int only */
  333.         write_scc(CTL+base,R1,TxINT_ENAB|EXT_INT_ENAB);  /* Tx/Extern ints on */
  334.         write_scc(CTL+base,R9,MIE|NV);        /* master enable */
  335.         /* enable interrupt latch on board */
  336.         outportb(hp->dmactrl,INTENABLE);
  337.  
  338.         hp->tstate = ACTIVE;    /* char going out now */
  339.         RESTORE();
  340.         return;
  341.  
  342.     case ACTIVE:
  343.         /* Here we are actively sending a frame */
  344.         if((c = PULLCHAR(&hp->sndbuf)) != -1){
  345.             outportb(hp->base+DATA,c);    /* next char is gone */
  346.             /* stuffing a char satisfies Interrupt condition */
  347.         } else {
  348.             /* No more to send - just stop till underrun int */
  349.             hp->tstate = UNDERRUN;
  350.             free_p(hp->sndbuf);
  351.             /* now we reset the EOM latch & enable underrun int */
  352.             write_scc(CTL+base,R0,RES_EOM_L);    /* send CRC at underrun */
  353.             write_scc(CTL+hp->base,R0,RES_Tx_P); /* reset Tx Int Pend */
  354.         }
  355.         RESTORE();
  356.         return;     /* back to wait for interrupt */
  357.  
  358.     case UNDERRUN:
  359.         /*
  360.          * This state is handled by an UNDERRUN interrupt, which
  361.          * is an External Status interrupt.  At UNDERRUN, the
  362.          * UNDERRUN/EOM latch in R0 will be 0, so the SCC will send
  363.          * CRC and ending flag.  After the CRC clears the Tx buffer,
  364.          * a TX BUFF EMPTY interrupt will fire.  At that time, we
  365.          * should be in FLAGOUT state, ready to send another frame
  366.          * if one is there to send.
  367.          */
  368.         break;
  369.     } /* end switch */
  370.     RESTORE();
  371. }
  372.  
  373. /* SET Transmit or Receive Mode
  374.  * Set RTS (request-to-send) to modem on Transmit
  375.  */
  376. static void
  377. rts(hp,x)
  378. struct egchan *hp;
  379. int16 x;
  380. {
  381. int16 tc;
  382. long br;
  383.  
  384.     /* Reprogram BRG and turn on transmitter to send flags */
  385.     if(x == ON) {                /* Turn Tx ON and Receive OFF */
  386.         write_scc(CTL+hp->base,R3,Rx8);    /* Rx off */
  387.         waitmsec(50);            /* 500 msec delay before on */
  388.         hp->rstate = IDLE;
  389.         write_scc(CTL+hp->base,R9,0);    /* Interrupts off */
  390.         br = hp->speed;         /* get desired speed */
  391.         tc = (XTAL/br)-2;        /* calc 1X BRG divisor */
  392.         write_scc(CTL+hp->base,R12,tc&0xFF);      /* lower byte */
  393.         write_scc(CTL+hp->base,R13,(tc>>8)&0xFF); /* upper bite */
  394.  
  395.         write_scc(CTL+hp->base,R5,TxCRC_ENAB|RTS|TxENAB|Tx8|DTR);
  396.         /* Transmitter now on */
  397.         write_scc(CTL+hp->base,R0,RES_Tx_CRC);/* CRC reset */
  398.         waitmsec(hp->txdelay);      /* Delay after Tx on */
  399.     } else {    /* Tx OFF and Rx ON */
  400.         hp->tstate = IDLE;
  401.         write_scc(CTL+hp->base,R5,Tx8|DTR);     /* TX off now */
  402.         write_scc(CTL+hp->base,R0,ERR_RES);     /* reset error bits */
  403.  
  404.         write_scc(CTL+hp->base,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  405.         write_scc(CTL+hp->base,R15,BRKIE);        /* allow ABORT int */
  406.  
  407.         /* delay for squelch tail before enable of Rx */
  408.         waitmsec(hp->squeldelay);    /* keep it up  */
  409.  
  410.         /* Reprogram BRG for 32x clock for receive DPLL */
  411.         write_scc(CTL+hp->base,R14,BRSRC);         /* BRG off, but keep Pclk source */
  412.         br = hp->speed;             /* get desired speed */
  413.         tc = ((XTAL/32)/br)-2;            /* calc 32X BRG divisor */
  414.         write_scc(CTL+hp->base,R12,tc&0xFF);    /* lower byte */
  415.         write_scc(CTL+hp->base,R13,(tc>>8)&0xFF);    /* upper bite */
  416.         write_scc(CTL+hp->base,R14,BRSRC|SEARCH);    /* SEARCH mode, keep BRG source */
  417.         write_scc(CTL+hp->base,R14,BRSRC|BRENABL);    /* Enable the BRG */
  418.  
  419.         /* Now, turn on the receiver and hunt for a flag */
  420.         write_scc(CTL+hp->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  421.         hp->rstate = ACTIVE;            /* Normal state */
  422.     }
  423. }
  424.  
  425. /* Initialize eg controller parameters */
  426. static void
  427. egchanparam(hp)
  428. struct egchan *hp;
  429. {
  430.     int16 tc;
  431.     long br;
  432.  
  433.     /* Initialize 8530 channel for SDLC operation */
  434.     int16 base = hp->base;
  435.  
  436.     DISABLE();
  437.  
  438. #ifdef    XXX
  439.     tprintf("Initializing Channel %c - Base = %x\n",base&2?'A':'B',base);
  440. #endif
  441.  
  442.     switch(base & 2){
  443.     case 2:
  444.         write_scc(CTL+base,R9,CHRA);    /* Reset channel A */
  445.         break;
  446.     case 0:
  447.         write_scc(CTL+base,R9,CHRB);    /* Reset channel B */
  448.         break;
  449.     }
  450.  
  451.     /* Deselect all Rx and Tx interrupts */
  452.     write_scc(CTL+base,R1,0);
  453.  
  454.     /* Turn off external interrupts (like CTS/CD) */
  455.     write_scc(CTL+base,R15,0);
  456.  
  457.     /* X1 clock, SDLC mode */
  458.     write_scc(CTL+base,R4,SDLC|X1CLK);           /* SDLC mode and X1 clock */
  459.  
  460.     /* Now some misc Tx/Rx parameters */
  461.     /* CRC PRESET 1, NRZI Mode */
  462.     write_scc(CTL+base,R10,CRCPS|NRZI);
  463.  
  464.     /* Set up BRG and DPLL multiplexers */
  465.     /* Tx Clk from BRG. Rcv Clk from DPLL, TRxC pin outputs DPLL */
  466.     write_scc(CTL+base,R11,TCBR|RCDPLL|TRxCDP|TRxCOI);
  467.  
  468.     /* Null out SDLC start address */
  469.     write_scc(CTL+base,R6,0);
  470.  
  471.     /* SDLC flag */
  472.     write_scc(CTL+base,R7,FLAG);
  473.  
  474.     /* Set up the Transmitter but don't enable it */
  475.     /*  DTR, 8 bit TX chars only - TX NOT ENABLED */
  476.     write_scc(CTL+base,R5,Tx8|DTR);
  477.  
  478.     /* Receiver - intial setup only - more later */
  479.     write_scc(CTL+base,R3,Rx8);            /* 8 bits/char */
  480.  
  481.     /* Setting up BRG now - turn it off first */
  482.     write_scc(CTL+hp->base,R14,BRSRC);         /* BRG off, but keep Pclk source */
  483.  
  484.     /* set the 32x time constant for the BRG in Receive mode */
  485.  
  486.     br = hp->speed;             /* get desired speed */
  487.     tc = ((XTAL/32)/br)-2;            /* calc 32X BRG divisor */
  488.  
  489.     write_scc(CTL+hp->base,R12,tc&0xFF);      /* lower byte */
  490.     write_scc(CTL+hp->base,R13,(tc>>8)&0xFF); /* upper bite */
  491.  
  492.     /* Time to set up clock control register for RECEIVE mode
  493.      * Eagle has xtal osc going to pclk at 3.6864 Mhz
  494.      * The BRG is sourced from that, and set to 32x clock
  495.      * The DPLL is sourced from the BRG, and feeds the TRxC pin
  496.      * Transmit clock & Receive clock come from DPLL
  497.      */
  498.  
  499.     /* Following subroutine sets up and ENABLES the receiver */
  500.     rts(hp,OFF);           /* TX OFF and RX ON */
  501.  
  502.     write_scc(CTL+hp->base,R14,BRSRC|SSBR);       /* DPLL from BRG, BRG source is PCLK */
  503.     write_scc(CTL+hp->base,R14,BRSRC|SEARCH);       /* SEARCH mode, keep BRG source */
  504.  
  505.     write_scc(CTL+hp->base,R14,BRSRC|BRENABL);    /* Enable the BRG */
  506.  
  507.     /* enable the receive interrupts */
  508.  
  509.     write_scc(CTL+hp->base,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  510.     write_scc(CTL+hp->base,R15,BRKIE);        /* ABORT int */
  511.     write_scc(CTL+hp->base,R9,MIE|NV);    /* master enable */
  512.  
  513.     /* enable interrupt latch on board */
  514.     outportb(hp->dmactrl,INTENABLE);
  515.  
  516.     /* Now, turn on the receiver and hunt for a flag */
  517.     write_scc(CTL+hp->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  518.  
  519.     RESTORE();
  520. }
  521.  
  522. /* Attach a EAGLE interface to the system
  523.  * argv[0]: hardware type, must be "eagle"
  524.  * argv[1]: I/O address, e.g., "0x300"
  525.  * argv[2]: vector, e.g., "2"
  526.  * argv[3]: mode, must be:
  527.  *        "ax25" (AX.25 UI frame format)
  528.  * argv[4]: interface label, e.g., "eg0"
  529.  * argv[5]: receiver packet buffer size in bytes
  530.  * argv[6]: maximum transmission unit, bytes
  531.  * argv[7]: interface speed, e.g, "1200"
  532.  *  notused:
  533.  * argv[8]: First IP address, optional (defaults to Ip_addr);
  534.  * argv[9]: Second IP address, optional (defaults to Ip_addr);
  535.  */
  536. int
  537. eg_attach(argc,argv,p)
  538. int argc;
  539. char *argv[];
  540. void *p;
  541. {
  542.     struct iface *if_pca, *if_pcb;
  543.     struct egchan *hp;
  544.     int dev;
  545.  
  546.     /* Quick check to make sure args are good and mycall is set */
  547.     if(*Mycall == '\0'){
  548.         tputs(Nomycall);
  549.         return -1;
  550.     }
  551.     if(if_lookup(argv[4]) != NULLIF) {
  552.         tprintf(Ifexist,argv[4]);
  553.         return -1;
  554.     }
  555.     if(strcmp(argv[3],"ax25") != 0) {
  556.         tputs("Mode must be ax25\n");
  557.         return -1;
  558.     }
  559.     /* Note: More than one card can be supported if you give up a COM:
  560.      * port, thus freeing up an IRQ line and port address
  561.      */
  562.     if(Egnbr >= EGMAX) {
  563.         tprintf("Max %d EAGLE controllers\n",EGMAX);
  564.         return -1;
  565.     }
  566.     dev = Egnbr++;
  567.  
  568.     /* Initialize hardware-level control structure */
  569.     Eagle[dev].addr = htoi(argv[1]);
  570.     Eagle[dev].vec = htoi(argv[2]);
  571.  
  572.     /* Save original interrupt vector */
  573.     Eagle[dev].oldvec = getirq(Eagle[dev].vec);
  574.  
  575.     /* Set new interrupt vector */
  576.     if(setirq(Eagle[dev].vec,eghandle[dev]) == -1){
  577.         tprintf("IRQ %u out of range\n",Eagle[dev].vec);
  578.         Egnbr--;
  579.         return -1;
  580.     }
  581.     /* Create interface structures and fill in details */
  582.     if_pca = mxallocw(sizeof(struct iface));
  583.     if_pcb = mxallocw(sizeof(struct iface));
  584.  
  585.     if_pca->addr = Ip_addr;
  586.     if_pcb->addr = Ip_addr;
  587.  
  588.     /* Append "a" and "b" to interface name */
  589.     if_pca->name = strxdup(argv[4]);
  590.     if_name(if_pca,"a");
  591.     if_pcb->name = strxdup(argv[4]);
  592.     if_name(if_pcb,"b");
  593.  
  594.     if_pcb->mtu = if_pca->mtu = atoi(argv[6]);
  595.     if_pcb->type = if_pca->type = CL_AX25;
  596.     if_pcb->ioctl = if_pca->ioctl = eg_ctl;
  597.     if_pca->dev = 2*dev;            /* eg0a */
  598.     if_pcb->dev = 2*dev + 1;        /* eg0b */
  599.     if_pcb->stop = if_pca->stop = eg_stop;
  600.     if_pcb->output = if_pca->output = ax_output;
  601.     if_pcb->raw = if_pca->raw = eg_raw;
  602.  
  603.     /* Must be true, was checked at top */
  604.     if_pcb->send = if_pca->send = ax_send;
  605.  
  606.     if_pcb->hwaddr = strxdup(Mycall);
  607.     if_pca->hwaddr = strxdup(Mycall);
  608.  
  609.     /* Link em in to the interface chain */
  610.     if_pca->next = if_pcb;
  611.     if_pcb->next = Ifaces;
  612.     if_pca->niface = Niface++;
  613.     if_pcb->niface = Niface++;
  614.     Ifaces = if_pca;
  615.  
  616.     /* set params in egchan table for CHANNEL B */
  617.  
  618.     hp = &Egchan[2*dev+1];                /* eg1 is offset 1 */
  619.     hp->iface = if_pcb;
  620.     hp->stata = Eagle[dev].addr + CHANA + CTL;    /* permanent status */
  621.     hp->statb = Eagle[dev].addr + CHANB + CTL;    /* addrs for CHANA/B*/
  622.     hp->dmactrl = Eagle[dev].addr + DMACTRL;    /* Eagle control reg */
  623.     hp->speed = (int16)atol(argv[7]);
  624.     hp->base = Eagle[dev].addr + CHANB;
  625.     hp->bufsiz = atoi(argv[5]);
  626.     hp->tstate = IDLE;
  627.     /* default KISS Params */
  628.     hp->txdelay = 25;        /* 250 Ms */
  629.     hp->persist = 64;        /* 25% persistence */
  630.     hp->slotime = 10;        /* 100 Ms */
  631.     hp->squeldelay = 20;        /* 200 Ms */
  632.  
  633.     write_scc(CTL+hp->stata,R9,FHWRES);     /* Hardware reset */
  634.                         /* one time only */
  635.     /* Disable interrupts with Master interrupt ctrl reg */
  636.     write_scc(CTL+hp->stata,R9,0);
  637.  
  638.     egchanparam(hp);
  639.  
  640.     /* Pre-allocate a receive buffer */
  641.     if((hp->rcvbuf = alloc_mbuf(hp->bufsiz)) == NULLBUF) {
  642.         /* No memory, abort receiver */
  643.         tputs("EGATTACH: No memory available for Receive buffers\n");
  644.         /* Restore original interrupt vector */
  645.         setirq(Eagle[dev].vec,Eagle[dev].oldvec);
  646.         Egnbr--;
  647.         return(-1);
  648.     }
  649.     hp->rcp = hp->rcvbuf->data;
  650.     hp->rcvbuf->cnt = 0;
  651.     hp->sndq = NULLBUF;
  652.  
  653.     /* set params in egchan table for CHANNEL A */
  654.     hp = &Egchan[2*dev];            /* eg0a is offset 0 */
  655.     hp->iface = if_pca;
  656.     hp->speed = (int16)atol(argv[7]);
  657.     hp->base = Eagle[dev].addr + CHANA;
  658.     hp->bufsiz = atoi(argv[5]);
  659.     hp->tstate = IDLE;
  660.     /* default KISS Params */
  661.     hp->txdelay = 25;        /* 250 Ms */
  662.     hp->persist = 64;        /* 25% persistence */
  663.     hp->slotime = 10;        /* 100 Ms */
  664.     hp->squeldelay = 20;        /* 200 Ms */
  665.  
  666.     egchanparam(hp);
  667.  
  668.     /* Pre-allocate a receive buffer */
  669.     if((hp->rcvbuf = alloc_mbuf(hp->bufsiz)) == NULLBUF) {
  670.         /* No memory, abort receiver */
  671.         tputs("EGATTACH: No memory available for Receive buffers\n");
  672.         /* Restore original interrupt vector */
  673.         setirq(Eagle[dev].vec,Eagle[dev].oldvec);
  674.         Egnbr--;
  675.         return -1;
  676.     }
  677.     hp->rcp = hp->rcvbuf->data;
  678.     hp->rcvbuf->cnt = 0;
  679.     hp->sndq = NULLBUF;
  680.  
  681.     write_scc(CTL+hp->base,R9,MIE|NV);        /* master interrupt enable */
  682.  
  683.     /* Enable interrupts on the EAGLE card itself */
  684.     outportb(hp->dmactrl,INTENABLE);
  685.  
  686.     /* Enable interrupt */
  687.     maskon(Eagle[dev].vec);
  688.  
  689.     return 0;
  690. }
  691.  
  692.  
  693. /* Shut down interface */
  694. static int
  695. eg_stop(iface,temp)
  696. struct iface *iface;
  697. int temp;
  698. {
  699.     int dev = iface->dev;
  700.  
  701.     if(dev & 1)
  702.         return 0;
  703.  
  704.     dev >>= 1;    /* Convert back into eagle number */
  705.  
  706.     /* Turn off interrupts */
  707.     maskoff(Eagle[dev].vec);
  708.  
  709.     /* Restore original interrupt vector */
  710.     setirq(Eagle[dev].vec,Eagle[dev].oldvec);
  711.  
  712.     /* Force hardware reset */
  713.     write_scc(CTL+Eagle[dev].addr + CHANA,R9,FHWRES);
  714.  
  715.     /* resets interrupt enable on eagle card itself */
  716.     outportb(Eagle[dev].addr+DMACTRL,0);
  717.     return 0;
  718. }
  719.  
  720. /* Send raw packet on eagle card */
  721. static int
  722. eg_raw(iface,bp)
  723. struct iface *iface;
  724. struct mbuf *bp;
  725. {
  726.     char kickflag;
  727.     struct egchan *hp;
  728.  
  729.     dump(iface,IF_TRACE_OUT,CL_AX25,bp);
  730.     hp = &Egchan[iface->dev];
  731.     kickflag = (hp->sndq == NULLBUF) & (hp->sndbuf == NULLBUF);    /* clever! flag=1 if something in queue */
  732.     enqueue(&hp->sndq,bp);
  733.     if(kickflag)            /* simulate interrupt to xmit */
  734.         egtxint(hp);        /* process interrupt */
  735.     return 0;
  736. }
  737. /* routine to delay n increments of 10 milliseconds
  738.  * about right on a turbo XT - will be slow on 4.77
  739.  * Still looking for a way to use the 8253 timer...
  740.  */
  741. static void
  742. waitmsec(n)
  743. int n;
  744. {
  745.     long i;
  746.  
  747.     for(i=0L; i < (200L*n); i++)
  748.         ;  /* simple loop delay */
  749. }
  750.  
  751. /* display EAGLE Channel stats */
  752. int
  753. doegstat(argc,argv,p)
  754. int argc;
  755. char *argv[];
  756. void *p;
  757. {
  758.     struct egchan *hp0;
  759.     int i;
  760.  
  761.     for(i=0; i< 2*EGMAX; i++) {
  762.         hp0 = &Egchan[i];
  763.  
  764.         tputs("EAGLE Board Statistics:\n\n");
  765.         tputs("Base Addr\tRxints\tTxints\tExints\tEnqued\tCrcerr\tAborts\tRxOvers\tRFrames\n");
  766.         tprintf("0x%x\t\t%ld\t%ld\t%ld\t%d\t%d\t%d\t%d\t%d\nRcv State=%s\n", hp0->base, hp0->rxints,
  767.             hp0->txints, hp0->exints, hp0->enqueued, hp0->crcerr, hp0->aborts,
  768.             hp0->rovers,hp0->rxframes,
  769.             hp0->rstate==0?"IDLE":hp0->rstate==1?"ACTIVE":hp0->rstate==2?"RXERROR":hp0->rstate==3?"RXABORT":"TOOBIG");
  770.     }
  771.     return 0;
  772. }
  773.  
  774. /* Subroutine to set kiss params in channel tables */
  775. static int32
  776. eg_ctl(struct iface *iface,int cmd,int set,int32 val)
  777. {
  778.     struct egchan *hp = &Egchan[iface->dev];        /* point to channel table */
  779.  
  780.     switch(cmd){
  781.     case PARAM_TXDELAY:
  782.         if(set)
  783.             hp->txdelay = (int)val;
  784.         return hp->txdelay;
  785.     case PARAM_PERSIST:
  786.         if(set)
  787.             hp->persist = (int)val;
  788.         return hp->persist;
  789.     case PARAM_SLOTTIME:
  790.         if(set)
  791.             hp->slotime = (int)val;
  792.         return hp->slotime;
  793.     case PARAM_TXTAIL:
  794.         if(set)
  795.             hp->squeldelay = (int)val;
  796.         return hp->squeldelay;
  797.     }
  798.     return -1;
  799. }
  800.  
  801. #endif /* EAGLE */